#include <iostream>
#include <vector>
#include <string>
#include <unistd.h>
#include "Mutex.hpp"

int tickets = 10000;
// 1、如何看待锁
//  a、锁，本身就是一个共享资源！全局变量要被保护，锁是用来保护全局资源的，但锁也是全局资源，锁的安全谁来保护？
//  b、pthread_mutex_lock，pthread_mutex_unlock:加锁、解锁过程必须是安全的  加锁的过程是原子的，要么成功要么失败，临界资源
//  c、如果申请成功就向后执行，如果申请暂时没有成功，执行流会如何？会阻塞，“挂起等待锁”
//  d、谁持有锁，谁进入临界区
// 2、如何理解加锁和解锁的本质 --- 加锁的过程是原子的
// 3、如果我们想简单的使用，该如何进行封装设计
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER

    class ThreadData
{
public:
    ThreadData(const std::string &threadname, pthread_mutex_t *mutex_p)
        : _threadname(threadname), _mutex_p(mutex_p)
    {
    }
    ~ThreadData()
    {
    }

public:
    std::string _threadname;
    pthread_mutex_t *_mutex_p;
};

void *getTicker(void *args)
{
    // ThreadData *td = static_cast<ThreadData *>(args);
    std::string username = static_assert<const char *>(args);
    while (true)
    {
        // 加锁和解锁的过程是多个线程串行执行的，程序运行速度变慢
        // 锁只规定互斥访问，没有规定必须谁来优先申请
        // 最后出现的结果就是线程竞争后的结果
        // pthread_mutex_lock(td->_mutex_p);
        // pthread_mutex_lock(&lock);                    // 持有锁的进程会被切换，但是其它线程无法访问，仍然在阻塞等待，直到该线程执行完
        {
            LockGuard lockguard(&lock); // RAII风格加锁
            if (tickets > 0)
            {
                usleep(1234);
                // std::cout << td->_threadname << " 正在进行抢票： " << tickets << std::endl;
                std::cout << username << " 正在进行抢票： " << tickets << std::endl;

                tickets--;
                // pthread_mutex_unlock(td->_mutex_p);
                // pthread_mutex_unlock(&lock);
            }
            else
            {
                // pthread_mutex_unlock(td->_mutex_p);
                // pthread_mutex_unlock(&lock);
                break;
            }
        }
        usleep(1000); // 形成一个订单给用户
    }

    return nullptr;
}

int main()
{
    // #define NUM 4
    //     pthread_mutex_t lock;
    //     pthread_mutex_init(&lock, nullptr);
    //     std::vector<pthread_t> tids(NUM);
    //     for (int i = 0; i < NUM; ++i)
    //     {
    //         char buffer[64];
    //         snprintf(buffer, sizeof buffer, "thread %d", i + 1);
    //         ThreadData *td = new ThreadData(buffer, &lock);
    //         pthread_create(&tids[i], nullptr, getTicker, td); // 创建新线程
    //     }

    //     for (const auto &tid : tids)
    //     {
    //         pthread_join(tid, nullptr); // 等待新线程
    //     }

    //      pthread_mutex_destroy(&lock);

    pthread_t t1, t2, t3, t4;
    pthread_create(&t1, nullptr, getTicker, (void *)"thread 1");
    pthread_create(&t2, nullptr, getTicker, (void *)"thread 2");
    pthread_create(&t3, nullptr, getTicker, (void *)"thread 3");
    pthread_create(&t4, nullptr, getTicker, (void *)"thread 4");

    pthread_join(t1, nullptr);
    pthread_join(t2, nullptr);
    pthread_join(t3, nullptr);
    pthread_join(t4, nullptr);

    return 0;
}